/**
 * 最终整合版本
 * 解析 docx 词条 + 所有批注（不遗漏）
 * 输出 Excel
 *
 * 作者：ChatGPT（按用户规则完全定制）
 */

const fs = require("fs");
const AdmZip = require("adm-zip");
const xml2js = require("xml2js");
const ExcelJS = require("exceljs");
const path = require("path");

// ==== 文件路径修改这里 ====
const INPUT_DOCX = path.join(process.cwd(), "docs/3.中途稿译文-中国民族史藏羌地区-12条全-20250221.docx");
const OUTPUT_XLSX = path.join(process.cwd(), "extracted_entries.xlsx");
// ==========================

// ================= 工具函数 =================
const clean = (s) =>
  (s || "")
    .replace(/\u00A0/g, " ")
    .replace(/\s+/g, " ")
    .trim();

const hasCJK = (s) => /[\u4e00-\u9fa5]/.test(s);
const isPinyin = (s) => /[a-zA-Zāáǎàōóǒòēéěèīíǐìūúǔùü]/.test(s);

// ================= 整段加粗判断 =================
function isWholeParagraphBold(wp) {
  if (!wp["w:r"]) return false;

  for (const r of wp["w:r"]) {
    const rPr = r["w:rPr"] && r["w:rPr"][0] ? r["w:rPr"][0] : null;
    const isBold = !!(rPr && (rPr["w:b"] || rPr["w:bCs"]));

    let hasText = false;

    if (r["w:t"]) {
      for (const t of r["w:t"]) {
        const text = typeof t === "string" ? t : t._ || "";
        if (text.trim().length > 0) {
          hasText = true;
          break;
        }
      }
    }

    if (hasText && !isBold) return false;
  }

  return true;
}

// ================= 提取段落文本 =================
function extractParagraphText(wp) {
  let out = [];

  function extractRuns(obj) {
    if (!obj) return;

    if (obj["w:t"]) {
      for (const t of obj["w:t"]) {
        out.push(typeof t === "string" ? t : t._ || "");
      }
    }

    if (obj["w:r"]) {
      for (const r of obj["w:r"]) extractRuns(r);
    }
  }

  extractRuns(wp);
  return clean(out.join(" "));
}

// ================= 捕获所有批注（完全不漏） =================
function extractCommentedTextOrdered(documentXmlObj) {
  const body = documentXmlObj["w:document"]["w:body"][0];
  const commented = {}; // id -> [text1, text2]
  const openRanges = {}; // id -> current accumulating text

  function pushComment(id, text) {
    if (!commented[id]) commented[id] = [];
    commented[id].push(clean(text));
  }

  function walk(node) {
    if (!node || typeof node !== "object") return;

    // Start range
    if (node["w:commentRangeStart"]) {
      for (const s of node["w:commentRangeStart"]) {
        const id = s["$"]["w:id"];
        openRanges[id] = "";
      }
    }

    // Text inside range
    if (node["w:t"]) {
      for (const t of node["w:t"]) {
        const text = typeof t === "string" ? t : t._ || "";
        for (const id in openRanges) {
          openRanges[id] += text + " ";
        }
      }
    }

    // commentReference（单点批注）
    if (node["w:commentReference"]) {
      for (const cr of node["w:commentReference"]) {
        const id = cr["$"]["w:id"];

        let txt = "";
        if (node["w:t"]) {
          for (const t of node["w:t"]) {
            txt += (typeof t === "string" ? t : t._ || "") + " ";
          }
        }

        if (txt.trim().length > 0) {
          pushComment(id, txt);
        }
      }
    }

    // End range
    if (node["w:commentRangeEnd"]) {
      for (const e of node["w:commentRangeEnd"]) {
        const id = e["$"]["w:id"];
        if (openRanges[id]) {
          pushComment(id, openRanges[id]);
          delete openRanges[id];
        }
      }
    }

    // Recursion
    for (const k in node) {
      const v = node[k];
      if (Array.isArray(v)) v.forEach(walk);
      else if (typeof v === "object") walk(v);
    }
  }

  walk(body);
  return commented;
}

// ================= 解析 comments.xml（批注内容） =================
async function parseCommentsXml(xmlStr) {
  const parser = new xml2js.Parser();
  const obj = await parser.parseStringPromise(xmlStr);

  const map = {};
  const cmts = obj["w:comments"]["w:comment"] || [];

  for (const c of cmts) {
    const id = c["$"]["w:id"];
    let texts = [];

    if (c["w:p"]) {
      for (const p of c["w:p"]) {
        if (p["w:r"]) {
          for (const r of p["w:r"]) {
            if (r["w:t"]) {
              for (const t of r["w:t"]) {
                texts.push(typeof t === "string" ? t : t._ || "");
              }
            }
          }
        }
      }
    }

    map[id] = clean(texts.join(" "));
  }

  return map;
}

// ================= 主解析 =================
async function parseDocx(docxPath) {
  const zip = new AdmZip(docxPath);

  const docXml = zip.getEntry("word/document.xml").getData().toString("utf-8");
  const commentsXml = zip.getEntry("word/comments.xml")
    ? zip.getEntry("word/comments.xml").getData().toString("utf-8")
    : "";

  const parser = new xml2js.Parser();
  const docObj = await parser.parseStringPromise(docXml);

  const commentedMap = extractCommentedTextOrdered(docObj);
  const commentsMap = commentsXml ? await parseCommentsXml(commentsXml) : {};

  const paragraphs = docObj["w:document"]["w:body"][0]["w:p"] || [];

  const blocks = paragraphs.map((p) => ({
    text: extractParagraphText(p),
    isBold: isWholeParagraphBold(p),
    raw: p,
  }));

  return { blocks, commentedMap, commentsMap };
}

// ================= 判断中文词目 + 拼音 =================
function isChineseTermParagraph(block) {
  if (!block.isBold) return false;

  const t = block.text;
  if (!t) return false;

  if (!hasCJK(t)) return false; // 必须有中文
  if (!isPinyin(t)) return false; // 必须有拼音

  if (/[:：]/.test(t)) return false;
  if (/^\d/.test(t)) return false;

  // 拼音必须在中文之后
  const idxP = t.search(/[a-zA-Zāáǎàōóǒòēéěèīíǐìūúǔùü]/);
  const idxC = t.search(/[\u4e00-\u9fa5]/);

  if (idxP <= idxC) return false;

  return true;
}

// ================= 提取中文词目和拼音 =================
function extractChineseTermAndPinyin(block) {
  const t = block.text;
  const m = t.match(/^([\u4e00-\u9fa5]+)\s+([a-zA-Zāáǎàōóǒòēéěèīíǐìūúǔùü\s]+)$/);

  if (m) {
    return { chinese_term: m[1].replace(/\s+/g, ""), pinyin: m[2].trim() };
  } else {
    return { chinese_term: t, pinyin: "" };  // 如果没有匹配到拼音部分，拼音字段为空
  }
}

// ================= 判断英文词目 =================
function isEnglishTermParagraph(block) {
  if (!block.isBold) return false;

  const t = block.text;
  if (!t) return false;

  if (hasCJK(t)) return false; //纯英文
  if (/[:：]/.test(t)) return false;

  if (/^\d/.test(t)) return false;
  if (/^(Abbreviated|Historical|Religious)/i.test(t)) return false;

  if (t.length > 40) return false;

  return true;
}

// ================= 构建词条 =================
function buildEntries(blocks, commentedMap, commentsMap) {
  const entries = [];
  let cur = null;
  let mode = ""; // zh/en

  for (const b of blocks) {
    // 中文词目
    if (isChineseTermParagraph(b)) {
      if (cur) entries.push(cur);

      cur = {
        chinese_term: "",
        pinyin: "",
        chinese_def: "",
        chinese_notes: "",
        english_term: "",
        english_def: "",
        zh_comments: [],
        en_comments: [],
      };

      mode = "zh";

      // 提取中文和拼音
      const { chinese_term, pinyin } = extractChineseTermAndPinyin(b);
      cur.chinese_term = chinese_term;
      cur.pinyin = pinyin;

      continue;
    }

    // 英文词目
    if (isEnglishTermParagraph(b) && cur) {
      cur.english_term = b.text;
      mode = "en";
      continue;
    }

    if (!cur) continue;

    // 注释 【注】 所有都归中文注释
    if (/【注】/.test(b.text)) {
      cur.chinese_notes += " " + b.text;
      continue;
    }

    // 中文释义 or 英文释义
    if (mode === "zh") cur.chinese_def += " " + b.text;
    else if (mode === "en") cur.english_def += " " + b.text;
  }

  if (cur) entries.push(cur);

  // ===== 分配批注 =====
  for (const id in commentedMap) {
    const pieces = commentedMap[id]; // 多条被批注内容
    const commentText = commentsMap[id] || "";

    for (const commentedText of pieces) {
      let assigned = false;

      for (const e of entries) {
        // 中文内匹配
        if (
          e.chinese_term.includes(commentedText) ||
          e.chinese_def.includes(commentedText)
        ) {
          e.zh_comments.push(`${commentedText}：${commentText}`);
          assigned = true;
          break;
        }

        // 英文内匹配
        if (
          e.english_term.includes(commentedText) ||
          e.english_def.includes(commentedText)
        ) {
          e.en_comments.push(`${commentedText}：${commentText}`);
          assigned = true;
          break;
        }
      }

      if (!assigned && entries.length) {
        entries[entries.length - 1].zh_comments.push(`${commentedText}：${commentText}`);
      }
    }
  }
  return entries;
}
// ================= 输出 Excel =================
async function exportExcel(entries, file) {
  const wb = new ExcelJS.Workbook();
  const ws = wb.addWorksheet("result");

  ws.columns = [
    { header: "中文词目", key: "chinese_term", width: 20 },
    { header: "拼音", key: "pinyin", width: 20 },
    { header: "中文释义", key: "chinese_def", width: 60 },
    { header: "中文注释", key: "chinese_notes", width: 40 },
    { header: "中文批注", key: "zh_comments", width: 50 },
    { header: "英文词目", key: "english_term", width: 25 },
    { header: "英文释义", key: "english_def", width: 60 },
    { header: "英文批注", key: "en_comments", width: 50 },
  ];

  for (const e of entries) {
    ws.addRow({
      chinese_term: clean(e.chinese_term),
      pinyin: clean(e.pinyin),
      chinese_def: clean(e.chinese_def),
      chinese_notes: clean(e.chinese_notes),
      zh_comments: e.zh_comments.join(" || "),
      english_term: clean(e.english_term),
      english_def: clean(e.english_def),
      en_comments: e.en_comments.join(" || "),
    });
  }

  await wb.xlsx.writeFile(file);
  return file;
}

// ================= MAIN =================
(async () => {
  console.log("解析 docx 中……");

  const { blocks, commentedMap, commentsMap } = await parseDocx(INPUT_DOCX);

  const entries = buildEntries(blocks, commentedMap, commentsMap);

  console.log("共解析词条：", entries.length);

  const out = await exportExcel(entries, OUTPUT_XLSX);
  console.log("Excel 已输出：", out);
})();
